package cn.smile.config.spring.shiro;

import cn.smile.config.key.RedisKey;
import cn.smile.dao.PermissionDaoMapper;
import cn.smile.dao.UserDaoMapper;
import cn.smile.pojo.User;
import cn.smile.service.RoleService;
import cn.smile.service.UserService;
import cn.smile.utils.GsonTool;
import com.alibaba.druid.sql.visitor.functions.Char;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: MaoSuyu
 * @User：John
 * @Date: 2019/7/2
 * @Time: 15:10
 * @Description: No Description
 */
public class WebShiroRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private PermissionDaoMapper permissionDaoMapper;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private GsonTool<String, String> gsonTool;


    @Override
    public String getName() {
        return this.getClass().getName();
    }

    /**
     * 授权
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("-------------------->授权<--------------------");
        final User user = (User) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //得到该用户角色信息
        List<String> roles = getRoles(user);
        //得到该用户权限信息
        List<String> permissions = getPermissions(user);
        //如果用户为maomao，则得到所有权限
        if ("maomao".equals(user.getUserName())) {
            authorizationInfo.addStringPermission("*:*");
            authorizationInfo.addRoles(getAllRoles(user));
            return authorizationInfo;
        }
        //封装角色和权限
        authorizationInfo.addRoles(roles);
        authorizationInfo.addStringPermissions(permissions);
        return authorizationInfo;
    }


    /**
     * 认证
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("-------------------->认证<--------------------");
        //前端传过来的用户信息
        User token = new User(authenticationToken.getPrincipal().toString(), new String((char[]) authenticationToken.getCredentials()));
        //从数据库中查询出用户信息
        final User dbUser = userService.login(token);
        if (dbUser == null) {
            return null;
        }
        //将id作为盐
        System.out.println(dbUser.toString());
        //盐
        ByteSource salt = ByteSource.Util.bytes(String.valueOf(dbUser.getId()));
        return new SimpleAuthenticationInfo(dbUser, dbUser.getUserPassword(), salt, getName());
    }


    private List<String> getRoles(User user) {
        List<String> roles = null;
        //去redis中查询用户角色
        final String rolesJson = redisTemplate.opsForValue().get(RedisKey.REDIS_SHIRO_ROLE_KEY + user.getId());
        //如果redis中没有角色
        if (null == rolesJson) {
            //从数据库得到该用户的所有角色
            roles = roleService.findRoleById(user);
            final String roleList = gsonTool.listToJson(roles);
            //将数据库查询到的数据插入redis
            redisTemplate.opsForValue().set(RedisKey.REDIS_SHIRO_ROLE_KEY + user.getId(), roleList);
            System.out.println("------->数据库查询完毕，已插入至redis中<-------");
        } else {
            roles = gsonTool.jsonToList(rolesJson, String.class);
            System.out.println("------->redis查询完毕，已得到数据进行转换<-------");
        }
        return roles;
    }

    private List<String> getPermissions(User user) {
        List<String> permissions = null;
        //去redis中查询用户权限
        final String permissionsJson = redisTemplate.opsForValue().get(RedisKey.REDIS_SHIRO_PERMISSION_KEY + user.getId());
        if (null == permissionsJson) {
            //从数据库得到该用户的所有权限
            permissions = permissionDaoMapper.selectPermissionById(user);
            final String permissionList = gsonTool.listToJson(permissions);
            redisTemplate.opsForValue().set(RedisKey.REDIS_SHIRO_PERMISSION_KEY + user.getId(), permissionList);
            System.out.println("------->数据库查询完毕，已插入至redis中<-------");
        } else {
            permissions = gsonTool.jsonToList(permissionsJson, String.class);
            System.out.println("------->redis查询完毕，已得到数据进行转换<-------");
        }
        return permissions;
    }

    private List<String> getAllRoles(User user) {
        List<String> roles = null;
        //去redis中查询是否有数据
        final String all = redisTemplate.opsForValue().get(RedisKey.REDIS_SHIRO_ROLE_ALL_KEY);
        if (null == all) {
            //去数据库中查询所有角色
            roles = roleService.findAll();
            final String rolesJson = gsonTool.listToJson(roles);
            //存储至redis
            redisTemplate.opsForValue().set(RedisKey.REDIS_SHIRO_ROLE_ALL_KEY, rolesJson);
        } else {
            roles = gsonTool.jsonToList(all, String.class);
        }
        return roles;
    }
}
